#pragma once

#include<iostream>
#include<map>
#include<functional>
#include<fcntl.h>

#include"Log.hpp"
#include"Connection.hpp"
#include"Epoll.hpp"

class Reactor
{
public:
    static const int eventSize=1024;
public:
    Reactor(int port,ConnectionSpace::func Accept)
    :_port(port),
    _isRunning(true)
    {
        //创建监听套接字
        _listenSocket=socket(AF_INET,SOCK_STREAM,0);
        if(_listenSocket<0)
        {
            Log(FATAL,"create listening socket error\n");
            return;
        }
        Log(DEBUG,"create listening socket %d successfully\n",_listenSocket);
        SetNoBlocking(_listenSocket);
        //设置地址复用
        int opt=1;
        if(setsockopt(_listenSocket,SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))<0)
        {
            Log(ERROR,"set address reuse error\n");
        }
        Log(DEBUG,"set address reuse succeffully\n");
        //绑定端口号
        struct sockaddr_in saddr;
        bzero(&saddr,sizeof(saddr));
        saddr.sin_family=AF_INET;
        saddr.sin_port=_port;
        saddr.sin_addr.s_addr=INADDR_ANY;
        
        if(bind(_listenSocket,(struct sockaddr*)(&saddr),sizeof(saddr))<0)
        {
            Log(FATAL,"bind error\n");
        }
        Log(DEBUG,"bind succeffully\n");
        //开启监听
        if(listen(_listenSocket,5)<0)
        {
            Log(FATAL,"listen error\n");
        }
        Log(DEBUG,"listen succeffully\n");

        Add(_listenSocket,EPOLLIN,nullptr,Accept,nullptr);
    }

    ~Reactor()
    {
        Delete(_listenSocket);
    }

    bool Delete(int fd)
    {
        _epoll.EpollDel(fd);
        close(fd);
        return _connections.erase(fd);
    }

    bool Add(int fd,uint32_t events,ConnectionSpace::func w=nullptr,ConnectionSpace::func r=nullptr,ConnectionSpace::func e=nullptr)
    {
        ConnectionSpace::Connection conn(fd,events,this,w,r,e);
        _connections[fd]=conn;
        return _epoll.EpollAdd(fd,events);
    }

    bool Modify(int fd,uint32_t events)
    {
        return _epoll.EpollMod(fd,events);
    }

    int GetListenSockfd()
    {
        return _listenSocket;
    }

    void SetNoBlocking(int fd) 
    {  
        int flags = fcntl(fd, F_GETFL, 0);  
        if (flags == -1) 
        {  
            Log(ERROR,"get fd status error\n");
            return;  
        }  
        flags |= O_NONBLOCK;  
        if (fcntl(fd, F_SETFL, flags) == -1) 
        {  
            Log(ERROR,"set fd noBlocking error\n");
        }  
    }

    void Start()
    {
        Log(DEBUG,"Reactor start\n");
        while(_isRunning)
        {
            int n=_epoll.EpollWait(_readyEvents,eventSize);
            if(n>0)
            {
                Log(DEBUG,"wait succeffully %d\n",n);
                while(n--)
                {
                    int fd=_readyEvents[n].data.fd;
                    uint32_t events=_readyEvents[n].events;
                    if(events&EPOLLIN)
                    {
                        _connections[fd]._read(_connections[fd]);
                    }
                    if(events&EPOLLOUT)
                    {
                        _connections[fd]._write(_connections[fd]);
                    }
                }
            }
            else if(0==n)
            {
                Log(DEBUG,"time out\n");
                continue;
            }
            else
            {
                Log(ERROR,"wait error\n");
                continue;
            }
        }
        _isRunning=false;
        Log(DEBUG,"Reactor exit\n");
    }
private:
    int _port;
    Epoll _epoll;
    int _listenSocket;
    bool _isRunning;
    struct epoll_event _readyEvents[eventSize];
    std::map<int,ConnectionSpace::Connection> _connections;
};